package com.wfh.mianshiji.tts;

import com.alibaba.dashscope.aigc.multimodalconversation.AudioParameters;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversation;
import com.alibaba.dashscope.aigc.multimodalconversation.MultiModalConversationParam;
import com.wfh.mianshiji.tts.model.SseMultiData;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Sinks;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;

/**
 * 增强的TTS流式服务，支持PCM到MP3/WAV的转换
 *
 * @author fenghuanwang
 */
@Slf4j
@Service
public class EnhancedTtsStreamingService {

    @Value("${tts.ali.model}")
    private String model;

    @Value("${tts.ali.voice}")
    private String voice;

    @Value("${spring.ai.dashscope.api-key}")
    private String apiKey;

    @Resource
    private AudioConverter audioConverter;

    @Resource
    private TtsStreamingService originalTtsService; // 原有的TTS服务

    // 更健壮的句子结束判断
    private static final Pattern SENTENCE_END_PATTERN = Pattern.compile(".*[。！？.!?…]$");

    /**
     * 流式文本转语音，支持PCM到MP3/WAV的转换
     *
     * @param textFlux 文本流
     * @param outputFormat 输出格式：mp3, wav, pcm（默认pcm）
     * @return 包含文本和音频的数据流
     */
    public Flux<SseMultiData> streamTextToAudioWithConversion(Flux<String> textFlux, String outputFormat) {
        if (outputFormat == null || outputFormat.trim().isEmpty()) {
            outputFormat = "pcm";
        }

        // 创建final变量用于lambda表达式
        final String finalOutputFormat = outputFormat;
        log.info("开始TTS流式转换，目标格式: {}", finalOutputFormat);

        Sinks.Many<SseMultiData> sink = Sinks.many().unicast().onBackpressureBuffer();
        StringBuilder buffer = new StringBuilder();
        AtomicBoolean completed = new AtomicBoolean(false);

        textFlux
                .doOnNext(token -> {
                    if (token == null || token.trim().isEmpty()) {
                        return;
                    }
                    String clean = sanitizeText(token);
                    if (clean.isEmpty()) {
                        return;
                    }

                    buffer.append(clean);
                    String current = buffer.toString().trim();

                    if (isCompleteSentence(current)) {
                        processSentenceWithConversion(current, sink, finalOutputFormat);
                        buffer.setLength(0); // 清空
                    }
                })
                .doOnComplete(() -> {
                    String remaining = buffer.toString().trim();
                    if (!remaining.isEmpty()) {
                        processSentenceWithConversion(remaining + "。", sink, finalOutputFormat);
                    }
                    if (completed.compareAndSet(false, true)) {
                        sink.tryEmitNext(SseMultiData.done());
                        sink.tryEmitComplete();
                        log.info("TTS流式转换完成");
                    }
                })
                .doOnError(error -> {
                    log.error("TTS流式转换异常", error);
                    if (completed.compareAndSet(false, true)) {
                        sink.tryEmitError(error);
                    }
                })
                .subscribe();

        return sink.asFlux();
    }

    /**
     * 处理单个句子的TTS转换
     */
    private void processSentenceWithConversion(String sentence, Sinks.Many<SseMultiData> sink, String outputFormat) {
        if (sentence == null || sentence.trim().isEmpty()) {
            return;
        }

        try {
            MultiModalConversationParam param = MultiModalConversationParam.builder()
                    .apiKey(apiKey)
                    .model(model)
                    .text(sentence)
                    .voice(AudioParameters.Voice.valueOf(voice))
                    .languageType("Chinese")
                    .build();

            MultiModalConversation conv = new MultiModalConversation();
            StringBuilder audioBuffer = new StringBuilder();

            // 收集所有音频chunk
            conv.streamCall(param)
                    .blockingForEach(result -> {
                        try {
                            String base64Audio = result.getOutput().getAudio().getData();
                            if (base64Audio != null && !base64Audio.isEmpty()) {
                                base64Audio = base64Audio.replaceAll("\\s", "");
                                // 直接收集base64字符串，避免重复解码
                                audioBuffer.append(base64Audio);
                            }
                        } catch (Exception e) {
                            log.warn("处理TTS chunk失败", e);
                        }
                    });

            // 解码PCM数据
            byte[] pcmData = Base64.getDecoder().decode(audioBuffer.toString());

            if (pcmData.length > 0) {
                byte[] convertedAudio = convertAudioFormat(pcmData, outputFormat);
                sink.tryEmitNext(new SseMultiData(sentence, convertedAudio));
                log.debug("句子TTS转换完成: '{}', 原始大小: {} bytes, 转换后大小: {} bytes",
                    sentence, pcmData.length, convertedAudio.length);
            } else {
                log.warn("句子无有效音频: {}", sentence);
            }

        } catch (Exception e) {
            log.error("TTS调用失败（句子: {}）", sentence, e);
        }
    }

    /**
     * 根据指定格式转换音频
     */
    private byte[] convertAudioFormat(byte[] pcmData, String outputFormat) {
        // 检测原始音频格式
        AudioConverter.AudioFormatInfo formatInfo = audioConverter.detectAudioFormat(pcmData);

        switch (outputFormat.toLowerCase()) {
            case "mp3":
                return audioConverter.convertPcmToMp3(
                    pcmData,
                    formatInfo.getSampleRate(),
                    formatInfo.getChannels(),
                    formatInfo.getSampleSizeInBits()
                );

            case "wav":
                return audioConverter.convertPcmToWav(
                    pcmData,
                    formatInfo.getSampleRate(),
                    formatInfo.getChannels(),
                    formatInfo.getSampleSizeInBits()
                );

            case "pcm":
            default:
                // 返回Base64编码的PCM数据
                String base64String = "data:audio/pcm;base64," + Base64.getEncoder().encodeToString(pcmData);
                return base64String.getBytes();
        }
    }

    /**
     * 创建支持多格式返回的SSE数据流
     * 返回格式：{"text": "文本内容", "audio": "音频数据(base64)", "format": "音频格式"}
     */
    public Flux<String> createMultiFormatSseStream(Flux<String> textFlux, String audioFormat) {
        // 创建final变量以在lambda中使用
        final String format = audioFormat != null ? audioFormat.toLowerCase() : "pcm";

        return streamTextToAudioWithConversion(textFlux, audioFormat)
                .map(data -> {
                    if (data.isDone()) {
                        return "{\"type\":\"done\"}";
                    } else {
                        String audioBase64 = new String(data.getAudio());
                        // 清理audio data URL前缀，只保留base64数据
                        if (audioBase64.startsWith("data:")) {
                            audioBase64 = audioBase64.substring(audioBase64.indexOf(",") + 1);
                        }

                        return String.format(
                            "{\"type\":\"chunk\",\"text\":\"%s\",\"audio\":\"%s\",\"format\":\"%s\"}",
                            escapeJson(data.getText()),
                            audioBase64,
                            format
                        );
                    }
                });
    }

    /**
     * 转义JSON字符串中的特殊字符
     */
    private String escapeJson(String str) {
        if (str == null) {
            return "";
        }
        return str.replace("\\", "\\\\")
                  .replace("\"", "\\\"")
                  .replace("\n", "\\n")
                  .replace("\r", "\\r")
                  .replace("\t", "\\t");
    }

    private boolean isCompleteSentence(String text) {
        if (text == null || text.length() < 2) {
            return false;
        }
        return text.matches(".*[\\u4e00-\\u9fa5a-zA-Z0-9].*")
                && SENTENCE_END_PATTERN.matcher(text).matches();
    }

    private static String sanitizeText(String input) {
        if (input == null) {
            return "";
        }
        return input
                .replaceAll("[\\p{C}\\u200B-\\u200D\\uFEFF\\u00AD]", "")
                .replaceAll("[\\*\\_\\#\\`\\<\\>\\[\\]\\(\\)\\|\\{\\}]+", "")
                .replaceAll("\\s+", " ")
                .trim();
    }
}